using Microsoft.Extensions.Logging;
using System.Collections.Concurrent;
using System.Text.Json;
using Uantek.Device.Communication.Models;
using Uantek.Device.Communication.Services.Interfaces;
using Uantek.Common.Cache;

namespace Uantek.Device.Communication.Services
{
    /// <summary>
    /// 数据收集服务实现
    /// </summary>
    public class DataCollectionService : IDataCollectionService
    {
        private readonly ILogger<DataCollectionService> _logger;
        private readonly IDeviceCommunicationService _deviceCommunicationService;
        private readonly ConcurrentDictionary<string, Timer> _collectionTimers;
        private readonly ConcurrentDictionary<string, CollectionConfig> _collectionConfigs;
        private readonly ConcurrentDictionary<string, List<DeviceDataModel>> _dataBuffer;
        private readonly object _lockObject = new object();

        public DataCollectionService(
            ILogger<DataCollectionService> logger,
            IDeviceCommunicationService deviceCommunicationService)
        {
            _logger = logger;
            _deviceCommunicationService = deviceCommunicationService;
            _collectionTimers = new ConcurrentDictionary<string, Timer>();
            _collectionConfigs = new ConcurrentDictionary<string, CollectionConfig>();
            _dataBuffer = new ConcurrentDictionary<string, List<DeviceDataModel>>();

            // 订阅设备数据接收事件
            _deviceCommunicationService.DeviceDataReceived += OnDeviceDataReceived;
        }

        public event EventHandler<DeviceDataModel>? DataCollected;
        public event EventHandler<(string DeviceId, Exception Error)>? CollectionError;

        public async Task<CommunicationResult> StartCollectionAsync(string deviceId, int collectionInterval = 1000)
        {
            try
            {
                if (_collectionTimers.ContainsKey(deviceId))
                {
                    return new CommunicationResult { Success = false, Message = $"设备 {deviceId} 的数据收集已经启动" };
                }

                var config = _collectionConfigs.GetOrAdd(deviceId, new CollectionConfig
                {
                    DeviceId = deviceId,
                    Interval = collectionInterval,
                    IsEnabled = true,
                    BatchSize = 100,
                    MaxRetryCount = 3
                });

                config.Interval = collectionInterval;
                config.IsEnabled = true;

                // 创建定时器
                var timer = new Timer(async _ => await CollectDeviceDataAsync(deviceId), 
                                    null, 
                                    TimeSpan.Zero, 
                                    TimeSpan.FromMilliseconds(collectionInterval));

                _collectionTimers.TryAdd(deviceId, timer);

                // 初始化数据缓冲区
                _dataBuffer.TryAdd(deviceId, new List<DeviceDataModel>());

                _logger.LogInformation($"设备 {deviceId} 数据收集启动成功，收集间隔: {collectionInterval}ms");
                return new CommunicationResult { Success = true, Message = "数据收集启动成功" };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"启动设备 {deviceId} 数据收集失败");
                return new CommunicationResult { Success = false, Message = $"启动数据收集失败: {ex.Message}" };
            }
        }

        public async Task<CommunicationResult> StopCollectionAsync(string deviceId)
        {
            try
            {
                if (!_collectionTimers.TryRemove(deviceId, out var timer))
                {
                    return new CommunicationResult { Success = false, Message = $"设备 {deviceId} 的数据收集未启动" };
                }

                timer.Dispose();

                if (_collectionConfigs.TryGetValue(deviceId, out var config))
                {
                    config.IsEnabled = false;
                }

                // 保存缓冲区中的数据
                await FlushDataBufferAsync(deviceId);

                _logger.LogInformation($"设备 {deviceId} 数据收集停止成功");
                return new CommunicationResult { Success = true, Message = "数据收集停止成功" };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"停止设备 {deviceId} 数据收集失败");
                return new CommunicationResult { Success = false, Message = $"停止数据收集失败: {ex.Message}" };
            }
        }

        public async Task<CommunicationResult> PauseCollectionAsync(string deviceId)
        {
            try
            {
                if (_collectionConfigs.TryGetValue(deviceId, out var config))
                {
                    config.IsEnabled = false;
                    _logger.LogInformation($"设备 {deviceId} 数据收集暂停成功");
                    return new CommunicationResult { Success = true, Message = "数据收集暂停成功" };
                }

                return new CommunicationResult { Success = false, Message = $"设备 {deviceId} 的数据收集配置不存在" };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"暂停设备 {deviceId} 数据收集失败");
                return new CommunicationResult { Success = false, Message = $"暂停数据收集失败: {ex.Message}" };
            }
        }

        public async Task<CommunicationResult> ResumeCollectionAsync(string deviceId)
        {
            try
            {
                if (_collectionConfigs.TryGetValue(deviceId, out var config))
                {
                    config.IsEnabled = true;
                    _logger.LogInformation($"设备 {deviceId} 数据收集恢复成功");
                    return new CommunicationResult { Success = true, Message = "数据收集恢复成功" };
                }

                return new CommunicationResult { Success = false, Message = $"设备 {deviceId} 的数据收集配置不存在" };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"恢复设备 {deviceId} 数据收集失败");
                return new CommunicationResult { Success = false, Message = $"恢复数据收集失败: {ex.Message}" };
            }
        }

        public async Task<CommunicationResult> SetCollectionConfigurationAsync(string deviceId, Dictionary<string, object> configuration)
        {
            try
            {
                var config = _collectionConfigs.GetOrAdd(deviceId, new CollectionConfig { DeviceId = deviceId });

                if (configuration.TryGetValue("interval", out var interval))
                {
                    config.Interval = Convert.ToInt32(interval);
                }
                if (configuration.TryGetValue("batchSize", out var batchSize))
                {
                    config.BatchSize = Convert.ToInt32(batchSize);
                }
                if (configuration.TryGetValue("maxRetryCount", out var maxRetryCount))
                {
                    config.MaxRetryCount = Convert.ToInt32(maxRetryCount);
                }
                if (configuration.TryGetValue("isEnabled", out var isEnabled))
                {
                    config.IsEnabled = Convert.ToBoolean(isEnabled);
                }

                _logger.LogInformation($"设备 {deviceId} 数据收集配置更新成功");
                return new CommunicationResult { Success = true, Message = "数据收集配置更新成功" };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"设置设备 {deviceId} 数据收集配置失败");
                return new CommunicationResult { Success = false, Message = $"设置数据收集配置失败: {ex.Message}" };
            }
        }

        public async Task<IEnumerable<DeviceDataModel>> GetHistoricalDataAsync(string deviceId, DateTime startTime, DateTime endTime)
        {
            try
            {
                var cacheKey = $"device_data:{deviceId}";
                var dataList = new List<DeviceDataModel>();

                // 从Redis获取历史数据
                var keys = await Task.Run(() => RedisServer.Cache.Keys($"{cacheKey}:*"));
                foreach (var key in keys)
                {
                    var dataJson = await Task.Run(() => RedisServer.Cache.Get(key));
                    if (!string.IsNullOrEmpty(dataJson))
                    {
                        var data = JsonSerializer.Deserialize<DeviceDataModel>(dataJson);
                        if (data != null && data.Timestamp >= startTime && data.Timestamp <= endTime)
                        {
                            dataList.Add(data);
                        }
                    }
                }

                return dataList.OrderBy(d => d.Timestamp);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"获取设备 {deviceId} 历史数据失败");
                return new List<DeviceDataModel>();
            }
        }

        public async Task<DeviceDataModel?> GetRealTimeDataAsync(string deviceId)
        {
            try
            {
                var cacheKey = $"device_realtime:{deviceId}";
                var dataJson = await Task.Run(() => RedisServer.Cache.Get(cacheKey));
                
                if (!string.IsNullOrEmpty(dataJson))
                {
                    return JsonSerializer.Deserialize<DeviceDataModel>(dataJson);
                }

                return null;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"获取设备 {deviceId} 实时数据失败");
                return null;
            }
        }

        public async Task<CommunicationResult<byte[]>> ExportDataAsync(string deviceId, DateTime startTime, DateTime endTime, string format = "JSON")
        {
            try
            {
                var data = await GetHistoricalDataAsync(deviceId, startTime, endTime);
                byte[] exportData;

                switch (format.ToUpper())
                {
                    case "JSON":
                        var jsonString = JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true });
                        exportData = System.Text.Encoding.UTF8.GetBytes(jsonString);
                        break;
                    case "CSV":
                        exportData = ConvertToCsv(data);
                        break;
                    default:
                        return new CommunicationResult<byte[]> { Success = false, Message = $"不支持的导出格式: {format}" };
                }

                return new CommunicationResult<byte[]> { Success = true, Data = exportData, Message = "数据导出成功" };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"导出设备 {deviceId} 数据失败");
                return new CommunicationResult<byte[]> { Success = false, Message = $"数据导出失败: {ex.Message}" };
            }
        }

        private async Task CollectDeviceDataAsync(string deviceId)
        {
            try
            {
                if (!_collectionConfigs.TryGetValue(deviceId, out var config) || !config.IsEnabled)
                {
                    return;
                }

                // 这里应该实现具体的数据收集逻辑
                // 暂时模拟数据收集
                var deviceData = new DeviceDataModel
                {
                    DeviceId = deviceId,
                    Timestamp = DateTime.Now,
                    DataType = "sensor",
                    DataValues = new Dictionary<string, object>
                    {
                        { "temperature", Random.Shared.NextDouble() * 100 },
                        { "pressure", Random.Shared.NextDouble() * 50 }
                    }
                };

                // 触发数据收集事件
                DataCollected?.Invoke(this, deviceData);

                // 缓存数据
                await CacheDeviceDataAsync(deviceData);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"收集设备 {deviceId} 数据失败");
                CollectionError?.Invoke(this, (deviceId, ex));
            }
        }

        private async Task CacheDeviceDataAsync(DeviceDataModel deviceData)
        {
            try
            {
                var cacheKey = $"device_data:{deviceData.DeviceId}:{deviceData.Timestamp:yyyyMMddHHmmss}";
                var realtimeKey = $"device_realtime:{deviceData.DeviceId}";
                var dataJson = JsonSerializer.Serialize(deviceData);

                // 缓存历史数据（设置过期时间）
                await Task.Run(() => RedisServer.Cache.Set(cacheKey, dataJson, TimeSpan.FromDays(30)));
                
                // 缓存实时数据
                await Task.Run(() => RedisServer.Cache.Set(realtimeKey, dataJson, TimeSpan.FromMinutes(10)));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"缓存设备数据失败: {deviceData.DeviceId}");
            }
        }

        private async Task FlushDataBufferAsync(string deviceId)
        {
            try
            {
                if (_dataBuffer.TryGetValue(deviceId, out var buffer) && buffer.Count > 0)
                {
                    // 批量保存缓冲区数据
                    foreach (var data in buffer)
                    {
                        await CacheDeviceDataAsync(data);
                    }

                    buffer.Clear();
                    _logger.LogInformation($"设备 {deviceId} 缓冲区数据刷新完成");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"刷新设备 {deviceId} 缓冲区数据失败");
            }
        }

        private void OnDeviceDataReceived(object? sender, DeviceDataModel e)
        {
            // 将接收到的设备数据添加到缓冲区
            if (_dataBuffer.TryGetValue(e.DeviceId, out var buffer))
            {
                lock (buffer)
                {
                    buffer.Add(e);
                    
                    // 如果缓冲区达到批量大小，触发批量处理
                    if (_collectionConfigs.TryGetValue(e.DeviceId, out var config) && 
                        buffer.Count >= config.BatchSize)
                    {
                        Task.Run(() => FlushDataBufferAsync(e.DeviceId));
                    }
                }
            }

            // 触发数据收集事件
            DataCollected?.Invoke(this, e);
        }

        private byte[] ConvertToCsv(IEnumerable<DeviceDataModel> data)
        {
            var csv = new System.Text.StringBuilder();
            csv.AppendLine("DeviceId,DeviceName,Timestamp,DataType,Quality,ProtocolName,TransportType,IsAlarm");

            foreach (var item in data)
            {
                csv.AppendLine($"{item.DeviceId},{item.DeviceName},{item.Timestamp:yyyy-MM-dd HH:mm:ss}," +
                             $"{item.DataType},{item.Quality},{item.ProtocolName},{item.TransportType},{item.IsAlarm}");
            }

            return System.Text.Encoding.UTF8.GetBytes(csv.ToString());
        }

        private class CollectionConfig
        {
            public string DeviceId { get; set; } = string.Empty;
            public int Interval { get; set; } = 1000;
            public bool IsEnabled { get; set; } = true;
            public int BatchSize { get; set; } = 100;
            public int MaxRetryCount { get; set; } = 3;
        }
    }
}